/**
 * Represents a Transaction and stores any necessary information
 * to identify the transaction across the whole system.
 *
 * Transactions are used to combine multiple operations to ensure all ACID properties are met.
 *
 * As multiple transactions may be performed concurrently, it is in your responsibility to
 * ensure that the data integrity of the respective indexes is not violated.
 *
 * Transactions may not span threads. If they do so, they have to do it serially.
 *
 */

#include <cstdlib>
#include <pthread.h>
#include <iostream>
#include <vector>
#include <exception>

#include "../include/contest_interface.h"
#include "../include/Index.h"
#include "../include/tx.h"
#include "../include/Iterator.h"
#include "../include/util.h"

using namespace std;

/**
 * Operation   (pointers, object)   RollBack              type    bool Done
 * Read           Null, Null       Nothing                00        T/F
 * Delete         Pointers,Record  Insert(Record)         01        T/F
 * Insert         Pointers,Record  Delete(Record)         10        T/F
 * Update         Pointers,Record  Update(oldValue)       11        T/F
 */
operation::operation() {
    this->ptr = NULL;
    this->dirty_flag = false;
    this->count_success_op = 0;
}

operation::operation(uint8_t type_, Iterator *ptr_, Record r_, bool done_) {
    this->ptr = ptr_;
    this->r = r_;
    this->type = type_;
    this->done_flag = done_;
    this->dup_flag = 0;
    this->count_success_op = 0;
}

operation::operation(uint8_t type_, Iterator *ptr_, Record r_, bool done_, uint8_t dup_) {
    this->ptr = ptr_;
    this->r = r_;
    this->type = type_;
    this->done_flag = done_;
    this->dup_flag = dup_;
    this->count_success_op = 0;
}

operation::~operation() {
    if (this->ptr != NULL) {
        delete[] this->ptr->value()->key.value;
        this->ptr == NULL;
    }
}

Transaction::~Transaction() {
    //  uint8_t temp_ = this->Tx_status();
    //  if (temp_ != 1 && temp != 3) {
    Transaction *temp = this;

    while (!this->operations->empty()) {
        operation *temp = this->operations->back();
        temp->~operation();
        this->operations->pop_back();
    }
    if (this->Tx_index() != NULL)
        this->Tx_index()->EndTransaction(&temp);
    if (this->Tx_get_ShadowSpace() != NULL)
        delete this->Tx_get_ShadowSpace();

    temp = NULL;

}

Transaction::Transaction() {
    this->operations = NULL; //list of operations done by the transaction
    this->ix = NULL;
    this->rejected = false;
    this->handled = false;
    this->auto_commit = false;
    this->shadowSpace = new ShadowSpace();
}

operation* Transaction::Tx_pop_opt() {
    operation *ret = this->operations->back();
    this->operations->pop_back();
    return ret;
}

bool Transaction::insertOpt(operation *op) {
    try {
        this->operations->push_back(op);
    } catch (...) {
        return false;
    }
    return true;
}

operation* Transaction::Tx_find_Record(Record* rec_) {
    std::vector< operation*>::iterator it = this->operations->begin();
    int res = recordCmp((*it)->r, *rec_);
    int size_ = this->operations->size();
    int i;
    if (res == 0)
        return *it;
    for (i = 0; i < size_; i++) {
        it++;
        res = recordCmp((*it)->r, *rec_);
        if (res == 0)
            return *it;
    }
    return NULL;
}
